const fs = require('fs')
const path = require('path')
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default
const babel = require('@babel/core')

const moduleAnalyser = (filename) => {
  const content = fs.readFileSync(filename, 'utf-8')
  // 获取抽象语法树
  const ast = parser.parse(content, {
    sourceType: 'module'
  })
  const dependencies = {}
  // 获取引入关系的文件
  traverse(ast, {
    ImportDeclaration({ node }) {
      // 讲路径修改为相对路径
      const dirname = path.dirname(filename)
      const newFile = './' + path.join(dirname, node.source.value).replace('\\', '/')
      dependencies[node.source.value] = newFile
    }
  })
  // 将代码转换成浏览器能运行的代码
  const { code } = babel.transformFromAst(ast, null, {
    presets: ['@babel/preset-env']
  })
  return {
    filename,
    dependencies,
    code
  }
}

// 获取入口文件的所有依赖
const makeDependenciesGraph = (entry) => {
  const entryModule = moduleAnalyser(entry)
  const graphArray = [entryModule]
  for (let i = 0; i < graphArray.length; i++) {
    const item = graphArray[i]
    const { dependencies } = item
    if (dependencies) {
      for (let j in dependencies) {
        graphArray.push(moduleAnalyser(dependencies[j]))
      }
    }
  }
  const graph = {}
  graphArray.forEach(item => {
    graph[item.filename] = {
      dependencies: item.dependencies,
      code: item.code
    }
  })
  return graph
}

// 生成代码
const generateCode = (entry) => {
  const graph = JSON.stringify(makeDependenciesGraph(entry))
  console.info(graph)
  return `
  (function(graph) {
    function require(module) {
      function localRequire(relativePath) {
        return require(graph[module].dependencies[relativePath])
      }
      var exports = {}
      !(function(require, exports, code){
        eval(code)
      })(localRequire, exports, graph[module].code)
      return exports
    }
    require('${entry}')
  })(${graph})
  `
}

const code = generateCode('./src/index.js')
// 注意：直接复制粘贴到浏览器把换行注意一下
console.log(code)
